home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 52
/
Mac Magazin and MacEasy Magazine CD - Issue 52.iso
/
Updates
/
Stata 5.0 Ado-files
/
ado.sea
/
newado
/
reshape.ado
< prev
next >
Wrap
Text File
|
1998-11-22
|
28KB
|
1,421 lines
*! version 4.0.3 13aug1998
program define reshape
version 5.0
if "`1'"=="clear" {
char _dta[ReS_ver]
char _dta[ReS_i]
char _dta[ReS_j]
char _dta[ReS_jv]
char _dta[ReS_Xij]
char _dta[Res_Xi]
char _dta[ReS_atwl]
char _dta[ReS_str]
exit
}
if "`1'"=="wide" | "`1'"=="long" {
DoNew `*'
exit
}
local syntax : char _dta[ReS_ver]
if "`1'"=="" | "`1'"==substr("query",1,length("`1'")) {
if "`syntax'"=="" | "`syntax'"=="v.2" {
Query
exit
}
local 1 "query"
}
if "`syntax'"=="" {
IfOld `1'
if $S_1 {
DoOld `*'
char _dta[ReS_ver] "v.1"
}
else {
DoNew `*'
char _dta[ReS_ver] "v.2"
}
exit
}
if "`syntax'"=="v.1" {
DoOld `*'
}
else DoNew `*'
end
program define IfOld
if "`1'"=="" {
global S_1 0
exit
}
local l = length("`1'")
if "`1'"==substr("groups",1,`l') | /*
*/ "`1'"==substr("vars",1,`l') | /*
*/ "`1'"==substr("cons",1,`l') | /*
*/ "`1'"==substr("query",1,`l') {
global S_1 1
exit
}
global S_1 0
end
program define IfNew
if "`1'"=="i" | "`1'"=="j" | "`1'"=="xij" | "`1'"=="xi" | /*
*/ "`1'"=="error" {
global S_1 1
}
else global S_1 0
end
program define DoNew
local c "`1'"
mac shift
if "`c'"=="i" {
if "`*'" == "" { error 198 }
unabbrev `*', max(10) min(1)
char _dta[ReS_i] "$S_1"
exit
}
if "`c'"=="j" {
J `*'
exit
}
if "`c'"=="xij" {
Xij `*'
exit
}
if "`c'"=="xi" {
if "`*'"=="" {
global S_1
}
else unabbrev `*'
char _dta[Res_Xi] "$S_1"
exit
}
if "`c'"=="" { /* reshape */
Query
exit
}
if "`c'"=="long" { /* reshape long */
if "`1'" != "" {
Simple long `*'
}
capture noisily Long `*'
Macdrop
exit _rc
}
if "`c'"=="wide" { /* reshape wide */
if "`1'" != "" {
Simple wide `*'
}
capture noisily Wide `*'
Macdrop
exit _rc
}
if "`c'"==substr("error",1,max(3,length("`c'"))) {
capture noisily Qerror `*'
Macdrop
exit
}
IfOld `c'
if $S_1 {
di in red "may not mix old and new syntax."
di in red "either use new syntax or " /*
*/ _quote "reshape clear" _quote /*
*/ " and start over using old syntax."
exit 198
}
error 198
end
program define Macdrop
mac drop ReS_j ReS_jv ReS_i ReS_Xij rVANS Res_Xi /*
*/ ReS_atwl ReS_str S_1 S_2
end
program define ReportL /* old_obs old_vars */
Report1 `1' `2' wide long
local n : word count $ReS_jv
di in gr "j variable (`n' values)" _col(43) "->" _col(48) /*
*/ in ye "$ReS_j"
di in gr "xij variables:"
parse "$ReS_Xij", parse(" ")
while "`1'"!="" {
RepF "`1'"
local skip = 39 - length("$S_1")
di in ye _skip(`skip') "$S_1" _col(43) in gr "->" /*
*/ in ye _col(48) "$S_2"
mac shift
}
di in gr _dup(77) "-"
end
program define RepF /* element from ReS_Xij */
local v "`1'"
if "$ReS_jv2" != "" {
local n : word count $ReS_jv2
parse "$ReS_jv2", parse(" ")
}
else {
local n : word count $ReS_jv
parse "$ReS_jv", parse(" ")
}
if `n'>=1 {
Subname `v' `1'
local list $S_1
}
if `n'>=2 {
Subname `v' `2'
local list `list' $S_1
}
if `n'==3 {
Subname `v' ``n''
local list `list' $S_1
}
else if `n'>3 {
Subname `v' ``n''
local list `list' ... $S_1
}
Subname `v' $ReS_atwl
global S_2 $S_1
global S_1 `list'
end
program define Report1 /* <#oobs> <#ovars> {wide|long} {long|wide} */
local oobs "`1'"
local ovars "`2'"
local wide "`3'"
local long "`4'"
di _n in gr "Data" _col(36) "`wide'" _col(43) "->" _col(47) "`long'" /*
*/ _n _dup(77) "-"
di in gr "Number of obs." _col(32) in ye %8.0g `oobs' /*
*/ in gr _col(43) "->" in ye %8.0g _N
quietly desc, short
di in gr "Number of variables" _col(32) in ye %8.0g `ovars' /*
*/ in gr _col(43) "->" in ye %8.0g _result(2)
end
program define ReportW /* old_obs old_vars */
Report1 `1' `2' wide long
local n : word count $ReS_jv2
local col = 31+(9-length("$ReS_j"))
di in gr "j variable (`n' values)" /*
*/ _col(`col') in ye "$ReS_j" in gr _col(43) "->" /*
*/ _col(48) "(dropped)"
di in gr "xij variables:"
parse "$ReS_Xij", parse(" ")
while "`1'"!="" {
RepF "`1'"
local skip = 39 - length("$S_2")
di in ye _skip(`skip') "$S_2" _col(43) in gr "->" /*
*/ in ye _col(48) "$S_1"
mac shift
}
di in gr _dup(77) "-"
end
program define Simple /* {wide|long} <funnylist>, i(varlist)
[j(varname [values])] */
local cmd "`1'"
mac shift
parse "`*'", parse(" ,")
while "`1'"!="" & "`1'"!="," {
local list `list' `1'
mac shift
}
if "`list'"=="" {
error 198
}
if "`1'" != "," {
di in red "option i() required"
exit 198
}
local options "I(string) J(string) ATwl(string) String"
parse "`*'"
if "`i'"=="" {
di in red "option i() required"
exit 198
}
unabbrev `i'
local i $S_1
if "`j'" != "" {
parse "`j'", parse(" ")
local jvar "`1'"
mac shift
local jvals "`*'"
}
else local jvar "_j"
if "`cmd'"=="wide" {
capture confirm var `jvar'
if _rc {
if _rc==111 {
di in red "`jvar' not found -- " _c
if "`jvar'"=="_j" {
di in red "specify j() option"
}
else di in red "data already wide"
exit 111
}
confirm var `jvar'
exit 198 /* just in case */
}
}
else {
capture confirm new var `jvar'
if _rc {
if _rc==110 {
di in red /*
*/ "`jvar' already defined -- data already long"
exit 110
}
confirm new var `jvar'
exit 198 /* just in case */
}
}
if "`atwl'"!="" {
local atwl "atwl(`atwl')"
}
if "`string'" != "" {
local string ", string"
}
reshape clear
reshape i `i'
reshape j `jvar' `jvals' `string'
reshape xij `list' `atwl'
end
program define Xij /* <names-maybe-with-@>[, atwl(string) */
if "`*'"=="" { error 198 }
parse "`*'", parse(" ,")
while "`1'" != "" & "`1'"!="," {
local list "`list' `1'"
mac shift
}
if "`list'"=="" {
error 198
}
local list `list'
if "`1'"=="," {
local options "ATwl(string)"
parse "`*'"
}
char _dta[ReS_Xij] "`list'"
char _dta[ReS_atwl] "`atwl'"
end
program define DoOld
local c "`1'"
local l = length("`c'")
mac shift
if "`c'"==substr("groups",1,`l') {
if "`2'" == "" {
error 198
}
DoNew j `*'
exit
}
if "`c'"==substr("vars",1,`l') {
DoNew xij `*'
exit
}
if "`c'"==substr("cons",1,`l') {
DoNew i `*'
exit
}
if "`c'"==substr("query",1,`l') {
local cons : char _dta[ReS_i]
local grpvar : char _dta[ReS_j]
local values : char _dta[ReS_jv]
local vars : char _dta[ReS_Xij]
local car : char _dta[Res_Xi]
di "group var: `grpvar'"
di "values: `values'"
di "cons: `cons'"
di "vars: `vars'"
exit
}
if "`c'"=="wide" {
DoNew wide `*'
exit
}
if "`c'"=="long" {
DoNew long `*'
exit
}
IfNew `c'
if $S_1 {
di in red "may not mix old and new syntax."
di in red "either use old syntax or " /*
*/ _quote "reshape clear" _quote /*
*/ " and start over using new syntax."
exit 198
}
error 198
end
program define Query
if "`*'"!="" {
error 198
}
local cons : char _dta[ReS_i]
local grpvar : char _dta[ReS_j]
local values : char _dta[ReS_jv]
local vars : char _dta[ReS_Xij]
local car : char _dta[Res_Xi]
local atwl : char _dta[ReS_atwl]
local isstr : char _dta[ReS_str]
if "`grpvar'"!="" {
capture confirm var `grpvar'
if _rc {
di _n in ye " (data is wide)"
}
else di _n in ye " (data is long)"
}
else di
if "`cons'"=="" {
local ccons "in gr"
local cons "<varlist>"
}
if "`grpvar'"=="" {
local cgrpvar "in gr"
local grpvar "<varname>"
if "`values'"=="" {
local values "[<#> - <#>]"
}
}
else if `isstr' {
local values "`values', string"
}
if "`vars'"=="" {
local cvars "in gr"
local vars "<varnames-without-#j-suffix>"
}
else {
if "`atwl'" != "" {
local vars "`vars', atwl(`atwl')"
}
}
if "`car'"=="" {
local ccar "in gr"
local car "<varlist>"
}
di in gr "+" _dup(77) "-" "+" _n /*
*/ "| Xij" _col(32) "| Command/contents" _col(79) "|" _n /*
*/ in gr "+" _dup(30) "-" "+" _dup(46) "-" "+"
di in gr "| Subscript i,j definitions:" _col(32) "|" _col(79) "|"
di in gr "| group id variable(s)" _col(32) "| reshape i " _c
Qlist 44 "`ccons'" `cons'
di in gr "| within-group variable" _col(32) "| reshape j " _c
Qlist 44 "`cgrpvar'" `grpvar' `values'
di in gr "| and its range" _col(32) "|" _col(79) "|"
di in gr "|" _col(32) "|" _col(79) "|"
di in gr "| Variable X definitions:" _col(32) "|" _col(79) "|"
di in gr "| varying within group" _col(32) "| reshape xij " _c
Qlist 46 "`cvars'" `vars'
di in gr "| constant within group (opt) | reshape xi " _c
Qlist 46 "`ccar'" `car'
di in gr "+" _dup(77) "-" "+"
local cons : char _dta[ReS_i]
local grpvar : char _dta[ReS_j]
local values : char _dta[ReS_jv]
local vars : char _dta[ReS_Xij]
local car : char _dta[Res_Xi]
if "`cons'"=="" {
di in gr "First type " _quote in white /*
*/ "reshape i" in gr _quote /*
*/ " to define the i variable."
exit
}
if "`grpvar'"=="" {
di in gr "Type " _quote in wh /*
*/ "reshape j" in gr _quote /*
*/ " to define the j variable and, optionally, values."
exit
}
if "`vars'"=="" {
di in gr "Type " _quote in wh /*
*/ "reshape xit" in gr _quote /*
*/ " to define variables that vary within i."
exit
}
if "`car'"=="" {
di in gr /*
*/ "Optionally type " _quote in wh "reshape xi" in gr _quote /*
*/ " to define variables that are constant within i."
}
capture confirm var `grpvar'
if _rc {
di in gr "Type " _quote in wh "reshape long" in gr _quote /*
*/ " to convert the data to long form."
exit
}
di in gr "Type " _quote in wh "reshape wide" in gr _quote /*
*/ " to convert the data to wide form."
end
program define Qlist /* col <optcolor> stuff */
local col `1'
local clr "`2'"
mac shift 2
while "`1'" != "" {
local l = length("`1'")
if `col' + `l' + 1 >= 79 {
local skip = 79 - `col'
di in gr _skip(`skip') "|" _n /*
*/ "|" _col(32) "| " _c
local col 34
}
di in ye `clr' "`1' " _c
local col = `col' + `l' + 1
mac shift
}
local skip = 79 - `col'
di in gr _skip(`skip') "|"
end
program define Qerror
Macros
Macros2 preserve
capture confirm var $ReS_j
if _rc==0 {
QerrorW
}
else QerrorL
end
/* ------------------------------------------------------------------------ */
program define Wide /* reshape wide */
local oldobs = _N
quietly describe, short
local oldvars = _result(2)
Macros
capture confirm var $ReS_j
if _rc {
di in blu "(already wide)"
exit
}
confirm var $ReS_j $rVANS $ReS_i $Res_Xi
capture confirm var _merge
if _rc ==0 {
di in red "cannot convert data containing variable _merge;"
di in red "drop or rename _merge"
exit 110
}
preserve
Macros2
if $S_1 {
restore, preserve
}
confirm var $ReS_j $Res_Xi
Veruniq
/*
Organization:
dataset dscons: (may not exist)
$ReS_i (1 obs per $ReS_i)
$Res_Xi
dataset dsvars:
$ReS_i (many obs per $ReS_i)
$ReS_j
$ReS_Xij
dataset dsnew:
$ReS_i (1 obs per $ReS_i)
<widened $VARS>
<$Res_Xi>
Note, ("`dscons'"!="") == ("$ReS_i"!="")
*/
tempfile dsnew dsvars hold
if "$Res_Xi" != "" {
tempfile dscons
}
quietly {
keep $ReS_j $rVANS $ReS_i $Res_Xi
sort $ReS_i $ReS_j
if "`dscons'"!="" {
save "`dscons'", replace /* temporarily */
drop $Res_Xi
save "`dsvars'", replace
use "`dscons'", clear
}
else save "`dsvars'", replace
by $ReS_i: keep if _n==1
if "`dscons'"!="" {
keep $ReS_i $Res_Xi
save "`dscons'", replace
}
keep $ReS_i
save "`dsnew'", replace
/* datasets initialized, now step through each value: */
globa ReS_jv2
parse "$ReS_jv", parse(" ")
while "`1'" != "" {
use "`dsvars'", clear
if $ReS_str {
keep if $ReS_j=="`1'"
}
else keep if $ReS_j == `1'
if _N==0 {
noi di in bl /*
*/ "(note: no data for $ReS_j == `1')"
capture use "`dsnew'", replace
}
else {
global ReS_jv2 $ReS_jv2 `1'
drop $ReS_j
noisily Widefix `1'
save "`hold'", replace
use "`dsnew'", clear
merge $ReS_i using "`hold'"
drop _merge
sort $ReS_i
save "`dsnew'", replace
}
mac shift
}
if "`dscons'" != "" {
merge $ReS_i using "`dscons'"
drop _merge
}
}
global S_FN
global S_FNDATE
if "`syntax'" != "v.1" {
sort $ReS_i
}
restore, not
local syntax: char _dta[ReS_ver]
if "`syntax'" != "v.1" {
ReportW `oldobs' `oldvars'
}
end
program define Veruniq
sort $ReS_i $ReS_j
capture by $ReS_i $ReS_j: assert _N==1
if _rc {
di in red "$ReS_j not unique within $ReS_i;"
di in red /*
*/ "there are multiple observations at the same $ReS_j" /*
*/ " within $ReS_i."
di in red "Type " _quote "reshape error" _quote /*
*/ " for a listing of the problem observations."
exit 9
}
if "$Res_Xi"=="" {
exit
}
sort $ReS_i $Res_Xi $ReS_j
tempvar cnt1 cnt2
quietly by $ReS_i: gen long `cnt1' = _N
quietly by $ReS_i $Res_Xi: gen long `cnt2' = _N
capture assert `cnt1' == `cnt2'
if _rc==0 {
exit
}
parse "$Res_Xi", parse(" ")
while "`1'"!="" {
capture by $ReS_i: assert `1'==`1'[1]
if _rc {
di in red "`1' not constant within $ReS_i"
}
mac shift
}
di in red "Type " _quote "reshape error" _quote /*
*/ " for a listing of the problem observations."
exit 9
end
program define QerrorW
confirm var $ReS_j $ReS_Xij $ReS_i $Res_Xi
sort $ReS_i $ReS_j
capture by $ReS_i $ReS_j: assert _N==1
if _rc {
Msg1
di in gr /*
*/ "The data are in the long form; j should be unique within i." _n
di in gr /*
*/ "There are multiple observations on the same " /*
*/ in ye "$ReS_j" in gr " within " /*
*/ in ye "$ReS_i" in gr "." _n
tempvar bad
quietly by $ReS_i $ReS_j: gen `bad' = _N!=1
quietly count if `bad'
di in gr /*
*/ "The following " _result(1) /*
*/ " out of " _N /*
*/ " observations have repeated $ReS_j values:"
list $ReS_i $ReS_j if `bad'
di in gr _n "(data now sorted by $ReS_i $ReS_j)"
exit
}
if "$Res_Xi"=="" {
di in gr "$ReS_j is unique within $ReS_i;"
di in gr "there is no error with which " /*
*/ _quote "reshape error" _quote " can help."
exit
}
sort $ReS_i $Res_Xi $ReS_j
tempvar cnt1 cnt2
quietly by $ReS_i: gen long `cnt1' = _N
quietly by $ReS_i $Res_Xi: gen long `cnt2' = _N
capture assert `cnt1' == `cnt2'
if _rc==0 {
di in gr "$ReS_j is unique within $ReS_i and"
di in gr "all the " _quote "reshape xi" _quote /*
*/ " variables are constant within $ReS_j;"
di in gr "there is no error with which " /*
*/ _quote "reshape error" _quote " can help."
exit
}
Msg1
local n : word count $ReS_Xij
if `n'==1 {
di in gr "xij variable is " in ye "$ReS_Xij" in gr "."
}
else di in gr "xij variables are " in ye "$ReS_Xij" in gr "."
di in gr "Thus, the following variable(s) should be constant within i:"
di in ye _col(7) "$Res_Xi"
sort $ReS_i $ReS_j
tempvar bad
parse "$Res_Xi", parse(" ")
while "`1'"!="" {
capture by $ReS_i: assert `1'==`1'[1]
if _rc {
qui by $ReS_i: gen long `bad' = /*
*/ cond(_n==_N,sum(`1'!=`1'[1]),0)
qui count if `bad'
di _n in ye "`1'" in gr " not constant within i (" /*
*/ in ye "$ReS_i" in gr ") for " /*
*/ _result(1) " value" _c
if _result(1)==1 {
di in gr " of i:"
}
else di in gr "s of i:"
qui by $ReS_i: replace `bad' = `bad'[_N]
list $ReS_i $ReS_j `1' if `bad'
drop `bad'
}
mac shift
}
di in gr _n "(data now sorted by $ReS_i $ReS_j)"
end
program define Msg1
di _n in gr "i (" in ye "$ReS_i" in gr /*
*/ ") indicates the top-level grouping such as subject id."
di in gr "j (" in ye "$ReS_j" in gr /*
*/ ") indicates the subgrouping such as time."
end
/*
Widefix #
Assumption when called: currently in memory are single observations
per $ReS_i coressponding to $ReS_j==#
go through $ReS_Xij and rename each ${ReS_Xij}#
*/
program define Widefix /* # */ /* reshape wide utility */
local val "`1'"
parse "$ReS_Xij", parse(" ")
while "`1'" != "" {
Subname `1' `val'
local new $S_1
capture confirm new var `new'
if _rc {
capture confirm var `new'
if _rc {
di in red "`new' implied name too long"
exit 198
}
else {
di in red "`new' already defined
exit 110
}
}
Subname `1' $ReS_atwl
rename $S_1 `new'
label var `new' "`val' $S_1"
mac shift
}
end
/* ------------------------------------------------------------------------ */
program define Long /* reshape long */
local oldobs = _N
quietly describe, short
local oldvars = _result(2)
Macros
confirm var $ReS_i $Res_Xi
capture confirm new var $ReS_j
if _rc {
di in blu "(already long)"
exit
}
preserve
Macros2
if $S_1 {
restore, preserve
}
confirm var $ReS_i $Res_Xi
tempfile new
Verluniq
quietly {
mkrtmpST
drop _all
set obs 1
if $ReS_str {
gen str8 $ReS_j = ""
}
else gen float $ReS_j = .
save "`new'", replace
parse "$ReS_jv", parse(" ")
while "`1'"!="" {
restore, preserve
noisily Longdo `1'
append using "`new'"
save "`new'", replace
mac shift
}
if $ReS_str {
drop if $ReS_j == ""
}
else drop if $ReS_j == .
global rtmpST
compress $ReS_j
}
global S_FN
global S_FNDATE
local syntax: char _dta[ReS_ver]
if "`syntax'" != "v.1" {
order $ReS_i $ReS_j
sort $ReS_i $ReS_j
}
restore, not
if "`syntax'" != "v.1" {
ReportL `oldobs' `oldvars'
}
end
program define Verluniq
local id : char _dta[ReS_i]
sort `id'
capture by `id': assert _N==1
if _rc {
di in red "i=`id' does not uniquely identify the observations;"
di in red "there are multiple observations " /*
*/ "with the same value of `id'."
di in red "Type " _quote "reshape error" _quote /*
*/ " for a listing of the problem observations."
exit 9
}
end
program define QerrorL
confirm var $ReS_i
local id "$ReS_i"
sort `id'
tempvar bad
quietly by `id': gen byte `bad' = _N!=1
capture assert `bad'==0
if _rc==0 {
di in gr "`id' is unique; there is no problem on this score"
exit
}
di _n in gr "i (" in ye "`id'" in gr /*
*/ ") indicates the top-level grouping such as subject id."
di _n in gr /*
*/ "The data are currently in the wide form; there should be be a single" /*
*/ _n "observation per i".
quietly count if `bad'
di _n in gr _result(1) " out of " _N /*
*/ " observations have duplicate i values:"
list `id' if `bad'
di in gr _n "(data now sorted by `id')"
end
program define mkrtmpST
global rtmpST
parse "$ReS_Xij", parse(" ")
while "`1'" != "" {
local ct "empty"
local i 1
local val : word `i' of $ReS_jv
while "`val'" != "" {
Subname `1' `val'
local van "$S_1"
capture confirm var `van'
if _rc==0 {
local nt : type `van'
Recast "`ct'" `nt'
local ct "$S_1"
if "`ct'"=="" {
noi di in red "`van' type mismatch with other `1' variables"
exit 198
}
}
else {
capture confirm new var `van'
if _rc {
di in red /*
*/ "`van' implied name too long"
exit 198
}
}
local i=`i'+1
local val : word `i' of $ReS_jv
}
if "`ct'"=="empty" {
local ct "byte"
}
global rtmpST "$rtmpST `ct'"
mac shift
}
end
program define Longdo /* reshape long dolist utility */
local val "`1'"
parse "$ReS_Xij", parse(" ")
local i 1
while "``i''" != "" {
Subname ``i'' `val'
local van "$S_1"
local vlist "`vlist' `van'"
local typ : word `i' of $rtmpST
local novar 1
capture confirm var `van'
if _rc == 0 {
capture confirm new var `van'
if _rc {
local novar 0
}
}
if `novar' {
di in bl "(note: `van' not found)"
if substr("`typ'",1,3)=="str" {
quietly gen `typ' `van' = ""
}
else quietly gen `typ' `van' = .
}
else recast `typ' `van'
local i=`i'+1
}
keep $ReS_i $Res_Xi `vlist'
if $ReS_str {
qui gen str8 $ReS_j = "`val'"
}
else qui gen float $ReS_j = `val'
parse "$ReS_Xij", parse(" ")
while "`1'" != "" {
Subname `1' `val'
local van "$S_1"
Subname `1' $ReS_atwl
local nvan "$S_1"
rename `van' `nvan'
label var `nvan'
mac shift
}
end
program define Recast /* recast command to maintain precision */
if "`1'"=="empty" | "`1'"=="`2'" {
global S_1 "`2'"
exit
}
local a "`1'"
local b "`2'"
local aisstr = substr("`a'",1,3)=="str"
local bisstr = substr("`b'",1,3)=="str"
if `aisstr'!=`bisstr' {
global S_1
exit
}
if "`a'"=="byte" {
global S_1 "`b'"
exit
}
global S_1 "`a'"
if "`a'"=="int" {
if "`b'"!="byte" {
global S_1 "`b'"
}
exit
}
if "`a'"=="long" {
if "`b'"!="byte" & "`b'"!="int" {
global S_1 "`b'"
}
exit
}
if "`a'"=="float" {
if "`b'"=="`double'" {
global S_1 "`b'"
}
exit
}
if "`a'"=="double" { exit }
local l1 = real(substr("`a'",4,.))
local l2 = real(substr("`b'",4,.))
if `l2'>`l1' {
global S_1 "`b'"
}
end
program define J /* reshape j [ #[-#] [...] | <str> <str> ...] [, string] */
if "`*'"=="" {
error 198
}
parse "`*'", parse(" -,")
local grpvar "`1'"
mac shift
local isstr 0
while "`1'"!="" & "`1'"!="," {
if "`2'" == "-" {
local i1 `1'
local i2 `3'
confirm integer number `i1'
confirm integer number `i2'
if `i1' >= `i2' {
di in red "`i1'-`i2': invalid range"
exit 198
}
while `i1' <= `i2' {
local values `values' `i1'
local i1 = `i1' + 1
}
mac shift 3
}
else {
capture confirm integer number `1'
local isstr = `isstr' | _rc
local values `values' `1'
mac shift
}
}
if "`1'"=="," {
local options "String"
parse "`*'"
if `isstr' & "`string'"=="" {
di in red /*
*/ "must also specify string option if string values are to be specified"
exit 198
}
if "`string'"!="" {
local isstr 1
}
}
Chkj `grpvar' `isstr'
char _dta[ReS_j] "`grpvar'"
char _dta[ReS_jv] "`values'"
char _dta[ReS_str] `isstr'
end
program define Chkj /* j whether-string */
local grpvar "`1'"
local isstr `2'
capture confirm var `grpvar'
if _rc { exit }
capture confirm string var `grpvar'
if _rc==0 {
if !`isstr' {
di in red "`grpvar' is string; specify string option"
exit 109
}
}
else {
if `isstr' {
di in red "`grpvar' is numeric"
exit 109
}
}
end
program define Macros /* reshape macro check utility */
global ReS_j : char _dta[ReS_j]
global ReS_jv : char _dta[ReS_jv]
global ReS_jv2
global ReS_i : char _dta[ReS_i]
global ReS_Xij : char _dta[ReS_Xij]
global Res_Xi : char _dta[Res_Xi]
global ReS_atwl : char _dta[ReS_atwl]
global ReS_str : char _dta[ReS_str]
local syntax : char _dta[ReS_ver]
if "$ReS_j"=="" {
if "`syntax'"=="v.1" {
NotDefd "reshape groups"
}
else NotDefd "reshape j"
}
capture confirm var $ReS_j
if _rc==0 {
Chkj $ReS_j $ReS_str
if $ReS_str==0 {
capture assert $ReS_j!=.
if _rc {
di in red "$ReS_j contains missing values"
exit 498
}
}
else {
capture assert trim($ReS_j)!=""
if _rc {
di in red "$ReS_j contains missing values"
exit 498
}
capture assert $ReS_j==trim($ReS_j)
if _rc {
di in red /*
*/ "$ReS_j has leading or trailing blanks"
exit 498
}
}
}
if "$ReS_jv"=="" {
if "`syntax'"=="v.1" {
NotDefd "reshape groups"
}
}
if "$ReS_i"=="" {
if "`syntax'"=="v.1" {
NotDefd "reshape cons"
}
else NotDefd "reshape i"
}
if "$ReS_Xij"=="" {
if "`syntax'"=="v.1" {
NotDefd "reshape vars"
}
else NotDefd "reshape xij"
}
global rVANS
parse "$ReS_Xij", parse(" ")
local i 1
while "``i''"!="" {
Subname ``i'' $ReS_atwl
global rVANS "$rVANS $S_1"
local i = `i' + 1
}
global S_1
end
program define Macros2 /* [preserve] */ /* returns S_1 */
local preserv "`1'"
/* determine whether anything to do */
capture confirm var $ReS_j
local islong = (_rc==0)
local dovalW 0
local dovalL 0
local docar 0
if "$ReS_jv"=="" {
if `islong' {
local dovalL 1
}
else local dovalW 1
}
if "$Res_Xi"=="" {
local syntax : char _dta[ReS_ver]
if "`syntax'"=="v.2" {
local docar 1
}
}
if `dovalL' {
FillvalL
}
/* nothing to do */
if `dovalW'==0 & `docar'==0 {
global S_1 0 /* S_1==0 -> data in memory unchanged */
exit
}
/* convert data to to names */
`preserv'
local varlist "req ex"
parse "_all"
quietly {
drop _all
local n : word count `varlist'
set obs `n'
gen str8 name = ""
parse "`varlist'", parse(" ")
local i 1
while `i' <= `n' {
replace name = "``i''" in `i'
local i = `i' + 1
}
}
/* call Fillval and FillXi as required */
if `dovalW' & `docar' {
tempfile dsname
quietly save "`dsname'"
FillvalW
quietly use "`dsname'", clear
FillXi `islong'
}
else if `dovalW' {
FillvalW
}
else FillXi `islong'
global S_1 1
end
program define NotDefd /* <message> */
di in red _quote "`*'" _quote " not defined"
exit 111
end
program define FillXi /* {1|0} */ /* 1 if islong currently */
local islong `1'
quietly {
if `islong' {
Dropout name $ReS_j $ReS_i
parse "$ReS_Xij", parse(" ")
local i 1
while "``i''" != "" {
Subname ``i'' $ReS_atwl
drop if name=="$S_1"
local i = `i' + 1
}
}
else { /* wide */
Dropout name $ReS_j $ReS_i
parse "$ReS_Xij", parse(" ")
local i 1
while "``i''" != "" {
local j 1
local jval : word `j' of $ReS_jv
while "`jval'"!="" {
Subname ``i'' `jval'
drop if name=="$S_1"
local j = `j' + 1
local jval : word `j' of $ReS_jv
}
local i = `i' + 1
}
}
local i 1
while `i' <= _N {
local nam = name[`i']
global Res_Xi $Res_Xi `nam'
local i = `i' + 1
}
}
end
program define Dropout /* varname varnames */
local name "`1'"
local i 2
while "``i''"!="" {
drop if `name'=="``i''"
local i = `i' + 1
}
end
program define FillvalL
Tab $ReS_j
end
program define Tab /* varname */
local v "`1'"
global ReS_jv
capture confirm string variable `v'
if _rc {
tempname rows
capture tabulate `v', matrow(`rows')
if _rc {
if _rc==1 { exit 1 }
local bad 1
}
else {
capture mat list `rows'
local bad = _rc
}
if `bad' {
/* theoretically cannot happen */
di in red "$ReS_j contains all missing values"
exit 498
}
local n = rowsof(`rows')
local i 1
while `i' <= `n' {
local el = `rows'[`i',1]
global ReS_jv $ReS_jv `el'
local i = `i' + 1
}
}
else { /* string ReS_j */
quietly {
sort `v'
tempvar one
by `v': gen byte `one' = _n>1
sort `one' `v'
local i 1
while `one'[`i']==0 {
local el = `v'[`i']
global ReS_jv $ReS_jv `el'
local i = `i' + 1
}
}
}
di in gr "(note: j = $ReS_jv)"
end
program define FillvalW
parse "$ReS_Xij", parse(" ")
tempvar u res
quietly {
local i 1
gen str8 `res' = ""
while "``i''" != "" {
local l = index("``i''","@")
local l = cond(`l'==0, length("``i''")+1,`l')
local lft = substr("``i''",1,`l'-1)
local rgt = substr("``i''",`l'+1,.)
local rgtl = length("`rgt'")
local minl = length("`lft'") + `rgtl'
gen byte `u' = length(name)>`minl' & /*
*/ substr(name,1,`l'-1)=="`lft'" & /*
*/ substr(name,-`rgtl',.) == "`rgt'"
/*
capture assert `res'=="" if `u'
if _rc {
di in red "logic error"
noi list
exit 9998
}
*/
replace `res' = substr(name,`l',.) if `u'
replace `res' = substr(`res',1,length(`res')-`rgtl') /*
*/ if `u'
capture assert `res'!="" if `u'
if _rc {
di in red "variable `lft'`rgt' already defined"
exit 110
}
drop `u'
local i = `i' + 1
}
capture assert `res'==""
if _rc==0 {
di in red "no xij variables found"
exit 111
}
}
if !$ReS_str {
tempvar num
qui gen float `num' = real(`res') if `res'!=""
Tab `num'
}
else Tab `res'
end
program define Subname /* <name-maybe-with-@> <tosub> */
local name "`1'"
local sub "`2'"
local l = index("`name'","@")
local l = cond(`l'==0, length("`name'")+1,`l')
local a = substr("`name'",1,`l'-1)
local c = substr("`name'",`l'+1,.)
global S_1 "`a'`sub'`c'"
end
exit